/*
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2006-2007 Intel Corporation. All Rights Reserved.
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_DVHD_VIDEO_ENCODER)

#include "umc_dv100_enc_1080_60i_segment_reader.h"
#include "umc_dv_enc_segment_compressor.h"
#include "umc_dv_enc_block.h"

namespace UMC
{

DV100_1080_60i_SegmentReader::DV100_1080_60i_SegmentReader(void):
    SegmentReader(10)
{

}

DV100_1080_60i_SegmentReader::~DV100_1080_60i_SegmentReader(void)
{
}

static const Ipp32s MBLumaWidth = 16;
static const Ipp32s MBChromaWidth = 8;
static const Ipp32s MBHeight = 16;
static const Ipp32s MBHalfHeight = 8;

static
void InitOffsets(size_t *YOffsets, size_t *UOffsets, size_t *VOffsets,
                 const size_t lPitches[], Ipp16s nDIFSeqNum, Ipp16s nVideoSegmentNum)
{
    Ipp32s MBNum;
    Ipp32s nChannelNum = nDIFSeqNum/10;
    nDIFSeqNum %= 10;
    Ipp32s s = nDIFSeqNum / 5;
    Ipp32s x = nDIFSeqNum % 5;
    Ipp32s t = (nVideoSegmentNum + 27*x) % 5;
    Ipp32s k = (nVideoSegmentNum + 27*x) / 5;
    Ipp32s h = nChannelNum;
    Ipp32s SuperBlockVertOrder[]=
    {
        (4*h + s + 2*t + 2) % 10, // a
        (4*h + s + 2*t + 6) % 10, // b
        (4*h + s + 2*t + 8) % 10, // c
        (4*h + s + 2*t + 0) % 10, // d
        (4*h + s + 2*t + 4) % 10  // e
    };
    Ipp32s SuperBlockHorzOrder[] = {2, 1, 3, 0, 4};

    size_t YPitch = lPitches[0];
    size_t UPitch = lPitches[1];
    size_t VPitch = lPitches[2];

    for(MBNum = 0; MBNum<5; MBNum++)
    {
        Ipp32s Row = k/9;
        Ipp32s Col = k%9;
        Ipp32s MBVertOrder =  h/2 + SuperBlockVertOrder[MBNum]*6 + Row*2;
        Ipp32s MBHorzOrder = (h%2 + SuperBlockHorzOrder[MBNum]*2 ) * 9 + Col;
        if( MBHorzOrder < 80 )
        {
            YOffsets[2*MBNum] = MBHeight * 4  * YPitch +    //skip 4 macro blocks from A0-A7
                                MBVertOrder * MBHeight * YPitch +
                                MBHorzOrder * MBLumaWidth;

            YOffsets[2*MBNum + 1] = YOffsets[2*MBNum] + YPitch * MBHalfHeight;


            UOffsets[2*MBNum] = MBHeight * 4  * UPitch +    //skip 4 macro blocks from A0-A7
                                MBVertOrder * MBHeight * UPitch +
                                MBHorzOrder * MBChromaWidth;

            UOffsets[2*MBNum + 1] = UOffsets[2*MBNum] + UPitch * MBHalfHeight;


            VOffsets[2*MBNum] = MBHeight * 4  * VPitch +    //skip 4 macro blocks from A0-A7
                                MBVertOrder * MBHeight * VPitch +
                                MBHorzOrder * MBChromaWidth;

            VOffsets[2*MBNum + 1] = VOffsets[2*MBNum] + VPitch * MBHalfHeight;
        }
        else if ( MBVertOrder < 4 * 8 )
        {
            //A0-A7
            Ipp32s A = MBVertOrder / 4;
            YOffsets[2*MBNum] =   (MBVertOrder % 4) * MBHeight * YPitch +
                                  (A * 10 + (MBHorzOrder - 80) ) * MBLumaWidth;
            YOffsets[2*MBNum+1] = YOffsets[2*MBNum] + YPitch * MBHalfHeight;


            UOffsets[2*MBNum] =   (MBVertOrder % 4) * MBHeight * UPitch +
                                  (A * 10 + (MBHorzOrder - 80) ) * MBChromaWidth;
            UOffsets[2*MBNum+1] = UOffsets[2*MBNum] + UPitch * MBHalfHeight;


            VOffsets[2*MBNum] =   (MBVertOrder % 4) * MBHeight * VPitch +
                                  (A * 10 + (MBHorzOrder - 80) ) * MBChromaWidth;
            VOffsets[2*MBNum+1] = VOffsets[2*MBNum] + VPitch * MBHalfHeight;
        }
        else if ( MBVertOrder < 4 * 8  + 3*8)
        {
            //A8-A15

            Ipp32s A = (MBVertOrder - 4 * 8) / 3;
            YOffsets[2*MBNum] =    (60 + 4) * MBHeight * YPitch + //Skip A0-A7 and main part of the frame
                                   ( (MBVertOrder - 4*8) % 3) * MBHeight * YPitch +
                                   (A * 10 + (MBHorzOrder - 80) ) * MBLumaWidth;

            YOffsets[2*MBNum+1] = YOffsets[2*MBNum] + YPitch * MBHalfHeight;


            UOffsets[2*MBNum] =    (60 + 4) * MBHeight * UPitch + //Skip A0-A7 and main part of the frame
                                   ( (MBVertOrder - 4*8) % 3) * MBHeight * UPitch +
                                   (A * 10 + (MBHorzOrder - 80) ) * MBChromaWidth;

            UOffsets[2*MBNum+1] = UOffsets[2*MBNum] + UPitch * MBHalfHeight;


            VOffsets[2*MBNum] =    (60 + 4) * MBHeight * VPitch + //Skip A0-A7 and main part of the frame
                                   ( (MBVertOrder - 4*8) % 3) * MBHeight * VPitch +
                                   (A * 10 + (MBHorzOrder - 80) ) * MBChromaWidth;

            VOffsets[2*MBNum+1] = VOffsets[2*MBNum] + VPitch * MBHalfHeight;
        }
        else
        {
            //B16

            YOffsets[2*MBNum] = (60 + 4 + 3) * MBHeight * YPitch + //Skip A0-A7, main part of the frame and A8-A15
                                ( (MBVertOrder - (4*8 + 3*8) ) * 10 + (MBHorzOrder - 80) ) * 32;

            YOffsets[2*MBNum+1] = YOffsets[2*MBNum] + MBLumaWidth;


            UOffsets[2*MBNum] = (60 + 4 + 3) * MBHeight * UPitch + //Skip A0-A7, main part of the frame and A8-A15
                                ( (MBVertOrder - (4*8 + 3*8) ) * 10 + (MBHorzOrder - 80) ) * 16;

            UOffsets[2*MBNum+1] = UOffsets[2*MBNum] + MBChromaWidth;


            VOffsets[2*MBNum] = (60 + 4 + 3) * MBHeight * VPitch + //Skip A0-A7, main part of the frame and A8-A15
                                ( (MBVertOrder - (4*8 + 3*8) ) * 10 + (MBHorzOrder - 80) ) * 16;

            VOffsets[2*MBNum+1] = VOffsets[2*MBNum] + MBChromaWidth;
        }
    }
}

static
inline
void ReadLine(Ipp16s *lpBlockData, Ipp16s LineNum, Ipp8u *lpcSrc)
{
    Ipp16s iX;
    for(iX=0; iX<8; iX++)
        lpBlockData[iX + LineNum*8] = ((Ipp16s) lpcSrc[iX]) - 128;
}

void DV100_1080_60i_SegmentReader::ReadMacroBlocks(size_t *YOffsets, size_t *UOffsets, size_t *VOffsets,
                                                   V_SEGMENT *lpVSegment, VideoData *pSrcFrame)
{
    Ipp8u *lpcSrcY, *lpcSrcU, *lpcSrcV;
    Ipp16s LineNum, MBNum;
    BLOCK *Y0, *Y1, *Y2, *Y3, *Cr0, *Cr1, *Cb0, *Cb1;

    for(MBNum=0; MBNum < 5; MBNum++)
    {
        Y0  = lpVSegment->m_pDCTBlocks + MBNum*8;
        Y1  = Y0 + 1;
        Y2  = Y0 + 2;
        Y3  = Y0 + 3;
        Cr0 = Y0 + 4;
        Cr1 = Y0 + 5;
        Cb0 = Y0 + 6;
        Cb1 = Y0 + 7;

        //Read top/left half of MB
        lpcSrcY = (Ipp8u*)pSrcFrame->GetPlanePointer(0) + YOffsets[MBNum*2];
        lpcSrcU = (Ipp8u*)pSrcFrame->GetPlanePointer(1) + UOffsets[MBNum*2];
        lpcSrcV = (Ipp8u*)pSrcFrame->GetPlanePointer(2) + VOffsets[MBNum*2];
        for (LineNum = 0;LineNum < 8;LineNum++)
        {
            ReadLine(Y0->m_lpsData, LineNum, lpcSrcY);
            ReadLine(Y1->m_lpsData, LineNum, lpcSrcY + 8);
            ReadLine(Cr0->m_lpsData, LineNum,   lpcSrcV);
            ReadLine(Cb0->m_lpsData, LineNum,   lpcSrcU);

            lpcSrcY += pSrcFrame->GetPlanePitch(0);
            lpcSrcU += pSrcFrame->GetPlanePitch(1);
            lpcSrcV += pSrcFrame->GetPlanePitch(2);
        }

        //Read bottom/right half of MB
        lpcSrcY = (Ipp8u*)pSrcFrame->GetPlanePointer(0) + YOffsets[MBNum*2+1];
        lpcSrcU = (Ipp8u*)pSrcFrame->GetPlanePointer(1) + UOffsets[MBNum*2+1];
        lpcSrcV = (Ipp8u*)pSrcFrame->GetPlanePointer(2) + VOffsets[MBNum*2+1];
        for (LineNum = 0;LineNum < 8;LineNum++)
        {
            ReadLine(Y2->m_lpsData, LineNum, lpcSrcY);
            ReadLine(Y3->m_lpsData, LineNum, lpcSrcY + 8);
            ReadLine(Cr1->m_lpsData, LineNum,   lpcSrcV);
            ReadLine(Cb1->m_lpsData, LineNum,   lpcSrcU);

            lpcSrcY += pSrcFrame->GetPlanePitch(0);
            lpcSrcU += pSrcFrame->GetPlanePitch(1);
            lpcSrcV += pSrcFrame->GetPlanePitch(2);
        }
    }
}

void DV100_1080_60i_SegmentReader::ReadSegment(struct V_SEGMENT *lpVSegment, Ipp16s DIFSeqOrder, Ipp16s VSegmentOrder)
{
    size_t YOffsets[10], UOffsets[10], VOffsets[10];
    size_t Pitches[3];
    Pitches[0] = m_lpSourceFrame->GetPlanePitch(0);
    Pitches[1] = m_lpSourceFrame->GetPlanePitch(1);
    Pitches[2] = m_lpSourceFrame->GetPlanePitch(2);

    InitOffsets(YOffsets, UOffsets, VOffsets, Pitches, DIFSeqOrder, VSegmentOrder);

    ReadMacroBlocks(YOffsets, UOffsets, VOffsets, lpVSegment, m_lpSourceFrame);
}

}//namespace UMC

#endif // (UMC_ENABLE_DVHD_VIDEO_ENCODER)
